package com.lib.image.widget

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
import timber.log.Timber
import kotlin.math.abs
import kotlin.math.pow

class RectView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) :
    View(context, attrs, defStyleAttr) {
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context) : this(context, null)

    private var mFrameHeight = 300
    private var mFrameWidth = 300
    private val mFrameRect = RectF()
    private val mMaxRectF = RectF()
    private val mPaint = Paint()
    private var mLastX = 0.0f
    private var mLastY = 0.0f
    private val strokeWidth = 8f
    private val mMinOffset = strokeWidth * 5
    private var pointer = false
    private var mFirstSet = true
    private var mFixed = true
    private var pointerCount = 0

    /**
     * 四角线的长度
     */
    private var mHandleSize = 40f

    /**
     * 四角线的笔宽度
     */
    private var mHandleWidth = 10f

    /**
     * 手指触摸的宽度
     */
    private var mTouchPadding = 10f

    private var mTouchAreaEnum = TouchAreaEnum.NONE

    init {
        mPaint.strokeWidth = strokeWidth
        mPaint.color = Color.WHITE
        mPaint.style = Paint.Style.STROKE
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)

        if (mFrameWidth > widthSize) {
            mFrameWidth = widthSize
        }
        if (mFrameHeight > heightSize) {
            mFrameHeight = height
        }

        val left = widthSize / 2 - mFrameWidth / 2
        val top = heightSize / 2 - mFrameHeight / 2
        val right = left + mFrameWidth
        val bottom = top + mFrameHeight
        mFrameRect.left = left.toFloat()
        mFrameRect.top = top.toFloat()
        mFrameRect.right = right.toFloat()
        mFrameRect.bottom = bottom.toFloat()
        setMeasuredDimension(widthSize, heightSize)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.drawRect(mFrameRect, mPaint)
    }

    private fun reDrawRect() {
        resetFrameRect()
        invalidate()
    }

    private fun resetFrameRect() {
        if (mMaxRectF.isEmpty) return
        if (mFrameRect.top < mMaxRectF.top) {
            mFrameRect.top = mMaxRectF.top
        }
        if (mFrameRect.bottom > mMaxRectF.bottom) {
            mFrameRect.bottom = mMaxRectF.bottom
        }
        if (mFrameRect.left < mMaxRectF.left) {
            mFrameRect.left = mMaxRectF.left
        }
        if (mFrameRect.right > mMaxRectF.right) {
            mFrameRect.right = mMaxRectF.right
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        super.onTouchEvent(event)
        when (event.action and  MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_POINTER_DOWN -> pointerCount += 1
            MotionEvent.ACTION_POINTER_UP -> pointerCount -= 1
            MotionEvent.ACTION_DOWN -> onActionDown(event)
            MotionEvent.ACTION_MOVE -> onActionMove(event)
            MotionEvent.ACTION_CANCEL -> clearStroke()
            MotionEvent.ACTION_UP -> clearStroke()
        }
        //如果超过边界或者不在框内，那么不做处理，返回false
        //如果是固定的，需要判断单指还是双指，如果双指，就不处理返回false
        return if(mFixed) {
            mTouchAreaEnum == TouchAreaEnum.LEFT
                    || mTouchAreaEnum == TouchAreaEnum.TOP
                    || mTouchAreaEnum == TouchAreaEnum.RIGHT
                    || mTouchAreaEnum == TouchAreaEnum.BOTTOM
                    || (mTouchAreaEnum == TouchAreaEnum.CENTER && pointerCount == 1)
        } else {
            mTouchAreaEnum != TouchAreaEnum.OUT_OF_BOUNDS && mTouchAreaEnum != TouchAreaEnum.CENTER
        }
    }

    private fun doublePointer(): Boolean {
        Timber.d("doublePointer $pointerCount")
        return pointerCount == 2
    }

    private fun onActionDown(event: MotionEvent): Boolean {
//        pointer = false
        pointerCount = 1
        mLastX = event.x
        mLastY = event.y
        handleTouchArea(event.x, event.y)
        if (mTouchAreaEnum == TouchAreaEnum.OUT_OF_BOUNDS) {
            return false
        }
        return false
    }

    private fun onActionMove(event: MotionEvent): Boolean {
        if (mTouchAreaEnum == TouchAreaEnum.OUT_OF_BOUNDS) {
            return false
        }
        if (doublePointer()) return false
        if (mFixed) {
            if(TouchAreaEnum.CENTER == mTouchAreaEnum) {
                moveCenterUpDown(event.y)
            } else {
                moveRect(event.y)
            }
            return false
        }
        when (mTouchAreaEnum) {
            TouchAreaEnum.RIGHT -> moveRight(event.x)
            TouchAreaEnum.TOP -> moveTop(event.y)
            TouchAreaEnum.BOTTOM -> moveBottom(event.y)
            TouchAreaEnum.LEFT -> moveLeft(event.x)
        }
        return false
    }

    /**
     * 点击框中间部分上下移动
     */
    private fun moveCenterUpDown(y: Float) {
        Timber.e("moveCenterUpDown lastY: $mLastY, y: $y")
        val h = mFrameRect.height()
        //上滑动
        //1269
        if(abs(y - mLastY) <= 5.0f) {
            mLastY = y
            return
        }
        if(y < mLastY) {
            Timber.e("moveCenterUpDown 上滑")
            mFrameRect.top = mFrameRect.top - (mLastY - y)
            mFrameRect.bottom = mFrameRect.bottom - (mLastY - y)
        } else if(y > mLastY) { //下滑
            Timber.e("moveCenterUpDown 下滑")
            mFrameRect.top = mFrameRect.top + (y - mLastY)
            mFrameRect.bottom = mFrameRect.bottom + (y - mLastY)
        }
        mLastY = y
        if (mFrameRect.top < mMaxRectF.top && mMaxRectF.top >= 0) { //
            mFrameRect.top = mMaxRectF.top
            mFrameRect.bottom = mFrameRect.top + h
        } else if (mFrameRect.top < 0 && mMaxRectF.top < 0) {
            mFrameRect.top = 0f
            mFrameRect.bottom = mFrameRect.top + h
        } else if (mFrameRect.bottom >= bottom) {
            mFrameRect.bottom = bottom.toFloat() - strokeWidth
            mFrameRect.top = mFrameRect.bottom - h
        } else if (mFrameRect.bottom >= mMaxRectF.bottom) {
            mFrameRect.bottom = mMaxRectF.bottom - strokeWidth
            mFrameRect.top = mFrameRect.bottom - h
        }
        reDrawRect()
    }

    /**
     * 只能移动上面的线和下面的，左右不可以
     */
    private fun moveRect(y: Float) {
        val h = mFrameRect.height()
        when (mTouchAreaEnum) {
            TouchAreaEnum.TOP -> {
                mFrameRect.top = y
                mFrameRect.bottom = y + h
            }
            TouchAreaEnum.BOTTOM -> {
                mFrameRect.top = y - h
                mFrameRect.bottom = y
            }
        }
        if (mFrameRect.top < mMaxRectF.top && mMaxRectF.top >= 0) { //
            mFrameRect.top = mMaxRectF.top
            mFrameRect.bottom = mFrameRect.top + h
        } else if (mFrameRect.top < 0 && mMaxRectF.top < 0) {
            mFrameRect.top = 0f
            mFrameRect.bottom = mFrameRect.top + h
        } else if (mFrameRect.bottom >= bottom) {
            mFrameRect.bottom = bottom.toFloat() - strokeWidth
            mFrameRect.top = mFrameRect.bottom - h
        } else if (mFrameRect.bottom >= mMaxRectF.bottom) {
            mFrameRect.bottom = mMaxRectF.bottom - strokeWidth
            mFrameRect.top = mFrameRect.bottom - h
        }
        reDrawRect()
    }

    private fun moveBottom(y: Float) {
        val top = mFrameRect.top
        var touchY = y
        if (touchY > measuredHeight) {
            touchY = measuredHeight.toFloat() - strokeWidth
        } else if (touchY < top + mMinOffset) {
            touchY = top + mMinOffset
        }
        mFrameRect.bottom = touchY
        reDrawRect()
    }

    private fun moveTop(y: Float) {
        val bottom = mFrameRect.bottom
        var touchY = y
        if (touchY < 0) {
            touchY = 0f + strokeWidth
        } else if (touchY > bottom - mMinOffset) {
            touchY = bottom - mMinOffset
        }
        mFrameRect.top = touchY
        reDrawRect()
    }

    private fun moveRight(x: Float) {
        val left = mFrameRect.left
        var touchX = x
        if (touchX > measuredWidth - strokeWidth) {
            touchX = measuredWidth.toFloat() - strokeWidth
        } else if (touchX < left + strokeWidth * 5) {
            touchX = left.toFloat() + strokeWidth * 5
        }
        mFrameRect.right = touchX
        reDrawRect()
    }

    private fun moveLeft(x: Float) {
        val right = mFrameRect.right
        var left = x
        if (left < 0 + strokeWidth) {
            left = 0f + strokeWidth
        } else if (left > right - mMinOffset) {
            left = right - mMinOffset
        }
        mFrameRect.left = left
        reDrawRect()
    }

    private fun moveFrame(diffX: Float, diffY: Float) {
        // 1.先平移
        mFrameRect.left += diffX.toInt()
        mFrameRect.right += diffX.toInt()
        mFrameRect.top += diffY.toInt()
        mFrameRect.bottom += diffY.toInt()
        reDrawRect()
        // 2.判断有没有超出界外，如果超出则后退
        handleMoveBounds()
    }

    private fun handleMoveBounds() {

    }

    private fun clearStroke() {
        pointer = false
        mTouchAreaEnum = TouchAreaEnum.NONE
    }

    /**
     * 确定触摸的区域
     */
    private fun handleTouchArea(x: Float, y: Float): Boolean {
        when {
            isInLeftTopCorner(x, y) -> {
                mTouchAreaEnum = TouchAreaEnum.LEFT_TOP
                return true
            }
            isInRightTopCorner(x, y) -> {
                mTouchAreaEnum = TouchAreaEnum.RIGHT_TOP
                return true
            }
            isInLeftBottomCorner(x, y) -> {
                mTouchAreaEnum = TouchAreaEnum.LEFT_BOTTOM
                return true
            }
            isInRightBottomCorner(x, y) -> {
                mTouchAreaEnum = TouchAreaEnum.RIGHT_BOTTOM
                return true
            }
            isInTopOrBottom(x, y) -> {
                return true
            }
            isInLeftOrRight(x, y) -> {
                return true
            }
            isInCenter(x, y) -> {
                return mFixed
            }
            else -> {
                mTouchAreaEnum = TouchAreaEnum.OUT_OF_BOUNDS
            }
        }
        return false
    }

    private fun isInCenter(x: Float, y: Float): Boolean {
        if(!mFixed) return false
        val contains = mFrameRect.contains(x, y)
        if(contains) {
            mTouchAreaEnum = TouchAreaEnum.CENTER
        }
        return contains
    }

    private fun isInLeftOrRight(x: Float, y: Float): Boolean {
        val left = mFrameRect.left
        val top = mFrameRect.top
        val right = mFrameRect.right
        val bottom = mFrameRect.bottom
        //在竖边框上
        if (y in top..bottom) {
            //在左边框上(在一定的误差范围内)
            // 390 - 24 = 3
            // 728
            if (x <= left + strokeWidth * 5 && x >= left - strokeWidth * 5) {
                clearStroke()
                mTouchAreaEnum = TouchAreaEnum.LEFT
                return true
            }
            //在右边框上(在一定的误差范围内)
            else if (x <= right + strokeWidth * 5 && x >= right - strokeWidth * 5) {
                clearStroke()
                mTouchAreaEnum = TouchAreaEnum.RIGHT
                return true
            }
        }
        return false
    }

    /**
     * 触摸范围是否在上或者下的框范围
     */
    private fun isInTopOrBottom(x: Float, y: Float): Boolean {
        val left = mFrameRect.left
        val top = mFrameRect.top
        val right = mFrameRect.right
        val bottom = mFrameRect.bottom
        //判断左右的范围内
        if (x in left..right) {
            //在上边框上(在一定的误差范围内)
            //314 + 12*5 = 374
            if (y <= top + strokeWidth * 5 && y >= top - strokeWidth * 5) {
                mTouchAreaEnum = TouchAreaEnum.TOP
                return true
            }
            //在下边框上(在一定的误差范围内)
            else if (y <= bottom + strokeWidth * 5 && y >= bottom - strokeWidth * 5) {
                mTouchAreaEnum = TouchAreaEnum.BOTTOM
                return true
            }
        }
        return false
    }

    /**
     * 触摸范围左上角
     */
    private fun isInLeftTopCorner(x: Float, y: Float): Boolean {
        val dx = x - mFrameRect.left
        val dy = y - mFrameRect.top
        return isInsideBound(dx, dy)
    }

    private fun isInRightTopCorner(x: Float, y: Float): Boolean {
        val dx = x - mFrameRect.right
        val dy = y - mFrameRect.top
        return isInsideBound(dx, dy)
    }

    private fun isInLeftBottomCorner(x: Float, y: Float): Boolean {
        val dx = x - mFrameRect.left
        val dy = y - mFrameRect.bottom
        return isInsideBound(dx, dy)
    }

    private fun isInRightBottomCorner(x: Float, y: Float): Boolean {
        val dx = x - mFrameRect.right
        val dy = y - mFrameRect.bottom
        return isInsideBound(dx, dy)
    }

    /**
     * 计算触摸点 是否在四个角的位置
     */
    private fun isInsideBound(dx: Float, dy: Float): Boolean {
        val d = dx.pow(2.0f) + dy.pow(2.0f)
        return (mHandleSize + mTouchPadding).pow(2.0f) >= d
    }

    fun isOutTouchArea(): Boolean {
        return mTouchAreaEnum == TouchAreaEnum.OUT_OF_BOUNDS || mTouchAreaEnum == TouchAreaEnum.NONE || mFixed
    }

    fun getFrameRect(): RectF {
        return mFrameRect
    }

    fun setMaxRect(displayRect: RectF) {
        mMaxRectF.set(displayRect)
        mMaxRectF.set(adjustRect(mMaxRectF))
    }

    fun setRect(displayRect: RectF) {
        if (mFirstSet) {
            val adjustLRRect = adjustLRRect(displayRect)
            mFrameRect.left = adjustLRRect.left
            mFrameRect.top = adjustLRRect.top
            mFrameRect.right = adjustLRRect.right
            mFrameRect.bottom = adjustLRRect.bottom
            reDrawRect()
            mFirstSet = false
        }
    }

    private fun adjustRect(rectF: RectF): RectF {
        if (rectF.top < 0 + strokeWidth) rectF.top += strokeWidth / 2
        if (rectF.bottom > measuredHeight - strokeWidth) rectF.bottom = measuredHeight - strokeWidth / 2
        if (rectF.left < 0 + strokeWidth) rectF.left += strokeWidth / 2
        if (rectF.right > measuredWidth - strokeWidth) rectF.right = measuredWidth - strokeWidth / 2
        return rectF
    }

    private fun adjustLRRect(rectF: RectF): RectF {
        var w = measuredWidth
        if(w <= 0) {
            val p = parent as FrameLayout
            w = p.measuredWidth
        }
        if (rectF.left < 0 + strokeWidth) rectF.left += strokeWidth / 2
        if (rectF.right > w - strokeWidth) rectF.right = w - strokeWidth / 2
        return rectF
    }

    fun setFixed(fixed: Boolean) {
        mFixed = fixed
    }

    /**
     * 手指点击的区域枚举类
     */
    internal enum class TouchAreaEnum {
        NONE,
        CENTER,
        LEFT_TOP,
        RIGHT_TOP,
        LEFT_BOTTOM,
        RIGHT_BOTTOM,
        OUT_OF_BOUNDS,
        LEFT,
        TOP,
        RIGHT,
        BOTTOM
    }
}